#ifndef PARSE_NODES_H
#define PARSE_NODES_H
#include "nodes/nodes.h"
#include "nodes/op_list.h"
#include "nodes/prim_nodes.h"

/**
 * query_t
 *    all statments are turned into a Query tree (via transformStmt)
 *    for further processing by the optimizer
 *    utility statements (i.e. non-optimizable statements)
 *    have the *utilityStmt field set.
 *
 * we need the isPortal flag because portal names can be null too; can
 * get rid of it if we support CURSOR as a commandType.
 */
typedef struct query_t {
	node_tag_t type;
	cmd_type_t command_type;	/* select|insert|update|delete|utility */
        node_t     *utility_stmt;   /* non-null if this is a non-optimizable statement */


	int		result_relation;	/* target relation (index to rtable) */
	char	*into;		    /* portal (cursor) name */
	bool	is_portal;	    /* is this a retrieve into portal? */
	bool	is_binary;	    /* binary portal? */

	char  	*unique_flag;	/* NULL, '*', or Unique attribute name */
	list_t	*sort_clause;	/* a list of SortClause's */

	list_t	*rtable;	    /* list of range table entries */
        list_t	*target_list;	/* target list (of target_entry_t) */
	node_t	*qual;		    /* qualifications */

	list_t	*group_clause;	/* list of columns to specified in GROUP BY */
	node_t	*having_qual;	/* qualification of each group */

	int		qry_numAgg;	    /* number of aggregates in the target list */

	/* internal to planner */
	list_t *base_relation_list;	/* base relation list */
	list_t *join_relation_list;	/* list of relations generated by joins */
	bool  query_is_archival;	/* archival query flag */
} query_t;

/* ----------------------
 *	Select Statement
 * ----------------------
 */
typedef struct select_stmt_t {
	node_tag_t		type;
	char        *unique;	/* NULL, '*', or unique attribute name */
	char		*into;		/* name of table (for select into
							   table) */
	list_t		*target_list;	/* the target list (of ResTarget) */
	list_t		*from_clause;	/* the from clause */
	node_t		*where_clause;	/* qualifications */
	list_t		*group_clause;	/* group by clause */
	node_t		*having_clause;	/* having conditional-expression */
	list_t		*order_clause;	/* sort clause (a list of SortBy's) */
} select_stmt_t;

typedef struct delete_stmt_t {
	node_tag_t  type;
	const char*       rel_name;
	node_t      *where_clause;
} delete_stmt_t;

typedef struct update_stmt_t {
	node_tag_t  type;
	const char*       rel_name;
	list_t*     target_list;
	node_t*     where_clause;
	list_t*     from_clause;
} update_stmt_t;

typedef struct insert_stmt_t {
	node_tag_t  type;
	const char*       rel_name;
	list_t*     cols;
	list_t*     exprs;
	list_t*     from_clause;
	node_t*     where_clause;
} insert_stmt_t;

typedef struct range_tbl_entry_t {
	node_tag_t	type;
	const char*       ref_name;	/* the reference name (specified in
							   the from clause) */
	const char*       rel_name;
	oid_t		rel_id;
	bool		in_from_cl;	/* comes from From Clause */
} range_tbl_entry_t;

/*
 * ResTarget -
 *    result target (used in target list of pre-transformed Parse trees)
 */
typedef struct res_target_t {
	node_tag_t	type;
	char		*name;		/* name of the result column */
	list_t		*indirection;	/* array references */
	node_t		*val;		/* the value of the result
					   (A_Expr or Attr) */
} res_target_t;

/*
 * Ident -
 *    an identifier (could be an attribute or a relation name). Depending
 *    on the context at transformStmt time, the identifier is treated as
 *    either a relation name (in which case, isRel will be set) or an
 *    attribute (in which case, it will be transformed into an Attr).
 */
typedef struct ident_t {
	node_tag_t	type;
	char		*name;		    /* its name */
	list_t		*indirection;	/* array references */
	bool		isRel;		    /* is a relation - filled in by
								   transformExpr() */
} ident_t;

/*
 * A_Expr - binary expressions
 */
typedef struct a_expr_t {
	node_tag_t	type;
	int			oper;		/* type of operation
					   {OP,OR,AND,NOT,ISNULL,NOTNULL} */
	char		*opname;	/* name of operator/function */
	node_t		*lexpr;		/* left argument */
	node_t		*rexpr;		/* right argument */
} a_expr_t;

/*
 * Attr -
 *    specifies an Attribute (ie. a Column); could have nested dots or
 *    array references.
 *
 */
typedef struct attr_t {
	node_tag_t      type;
	list_t*         attrs;
	char*           rel_name;
} attr_t;

/*
 * ColumnDef - column definition (used in various creates)
 */
typedef struct column_def_t {

} column_def_t;

/*
 * type_name_t - specifies a type in definitions
 */
typedef struct type_name_t {
	node_tag_t  type;
	const char*       name;
	int         length;
} type_name_t;

/*
 * DefElem -
 *    a definition (used in definition lists in the form of defname = arg)
 */
typedef struct def_elem_t {

} def_elem_t;

/*
 * ParamString - used in with clauses
 */
typedef struct param_string_t {

} param_string_t;

/*
 * Sortby - for order by clause
 */
typedef struct sort_by_t {
	node_tag_t	type;
	char		*name;		/* name of column to sort on */
	char		*use_op;		/* operator to use */
} sort_by_t;

/* ----------------------
 *	Create Index Statement
 * ----------------------
 */
typedef struct index_elem_t {

} index_elem_t;

/*
 * time_range_t - specifies a time range
 */
typedef struct time_range_t {
	node_tag_t		type;
	char		*start_date;
	char		*end_date;	/* snapshot if NULL */
} time_range_t;

/*
 * RelExpr - relation expressions
 */
typedef struct rel_expr_t {
	node_tag_t      type;
	char*           rel_name;
	bool            inh;    /* inheritance query */
	time_range_t*   time_range;	/* the time range */
} rel_expr_t;

/*
 * RangeVar - range variable, used in from clauses
 */
typedef struct range_var_t {
	node_tag_t      type;
	rel_expr_t*     rel_expr;   /* the relation expr */
	char*           name;       /* the name to referenced(optional) */
} range_var_t;

/*
 * time_range_t - specifies a time range
 */
typedef struct time_rang_t {

} time_rang_t;

/*
 * A_Indices - array reference or bounds ([lidx:uidx] or [uidx])
 */
typedef struct a_indices_t {
	node_tag_t  type;
	node_t      *lidx;
	node_t      *uidx;
} a_indices_t;

/*
 * ParamNo - specifies a parameter reference
 */
typedef struct param_no_t {

} param_no_t;

/* ----------------------
 *	Create Version Statement
 * ----------------------
 */
typedef struct version_stmt_t {

} version_stmt_t;

/* ----------------------
 *	Create {Operator|Type|Aggregate} Statement
 * ----------------------
 */
typedef struct define_stmt_t {

} define_stmt_t;

/* ----------------------
 *	Purge Statement
 * ----------------------
 */
typedef struct purge_stmt_t {

} purge_stmt_t;

/* ----------------------
 *	Create Rule Statement
 * ----------------------
 */
typedef struct rule_stmt_t {

} rule_stmt_t;

/*
 * A_Const - a constant expression
 */
typedef struct a_const_t {
	node_tag_t		type;
	parse_value_t         val;		/* the value (with the tag) */
	type_name_t		*type_name;	/* typecast */
} a_const_t;

typedef enum relation_type_t {
	TABLE_W3,
	TABLE_UNIT,
	TABLE_POINT,
	TABLE_ATTR
} relation_type_t;

typedef struct relation_t {
	uint16          r_ref_cnt;
	oid_t           r_id;
	relation_type_t r_type;
} relation_t;

/* ----------------------
 *	Notify Statement
 * ----------------------
 */
typedef struct notify_stmt_t {
    node_tag_t		type;
    char		*rel_name;	/* relation to notify */
} notify_stmt_t;

/* ----------------
 * oper_t
 *	opno 		- PG_OPERATOR OID of the operator
 *	opid 		- PG_PROC OID for the operator
 *	opresulttype 	- PG_TYPE OID of the operator's return value
 *	opsize 		- size of return result (cached by executor)
 *	op_fcache	- XXX comment me.
 *
 * ----
 * NOTE: in the good old days 'opno' used to be both (or either, or
 * neither) the pg_operator oid, and/or the pg_proc oid depending
 * on the postgres module in question (parser->pg_operator,
 * executor->pg_proc, planner->both), the mood of the programmer,
 * and the phase of the moon (rumors that it was also depending on the day
 * of the week are probably false). To make things even more postgres-like
 * (i.e. a mess) some comments were referring to 'opno' using the name
 * 'opid'. Anyway, now we have two separate fields, and of course that
 * immediately removes all bugs from the code...	[ sp :-) ].
 * ----------------
 */
typedef struct oper_t {
    node_tag_t  type;

    oid_t   op_no;
    oid_t   op_id;
    oid_t   op_result_type;
    int     op_size;
} oper_t;

/*
 * target_entry_t -
 *     a target  entry (used in the transformed target list)
 *
 * one of resdom or fjoin is not NULL. a target list is
 *	((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
 */
typedef struct target_entry_t {
    node_tag_t		type;
    node_t		*expr;		/* can be a list too */
} target_entry_t;

typedef struct var_t {
    node_tag_t		type;
    index_t		varno;
    attr_number_t	varattno;
    oid_t		vartype;
} var_t;

typedef struct resdom_t {
    node_tag_t		type;
    attr_number_t       resno;
    char		*resname;
} resdom_t;

/*
 * group_clause_t -
 *     used in the GROUP BY clause
 */
typedef struct group_clause_t {
    node_tag_t		type;
    var_t		*grp_attr;	/* attributes to group on */
    oid_t		grp_op_oid;	/* the sort operator to use */
} group_clause_t;

/*-------------------------
 * string_info_data_t holds information about a string.
 * 	'data' is the string.
 *	'len' is the current string length (as returned by 'strlen')
 *	'maxlen' is the size in bytes of 'data', i.e. the maximum string
 *		size (includeing the terminating '\0' char) that we can
 *		currently store in 'data' without having to reallocate
 *		more space.
 */
typedef struct string_info_data_t {
    char *data;
    int maxlen;
    int len;
} string_info_data_t;

typedef string_info_data_t *string_info_t;



#endif // PARSE_NODES_H
